#include "gazeTracker.h"

#define THRESHOLD 10

CvFont              myFont;
CvRect			   *faceRec;
CvRect			   *lEyeRec;
CvRect			   *rEyeRec;
float			   *lPupilRec;
float			   *rPupilRec;

CvSeq			   *lPupils;
CvSeq			   *rPupils;

// cascades used to find the face and eyes
CvHaarClassifierCascade* faceCascade;
CvHaarClassifierCascade* lEyeCascade;
CvHaarClassifierCascade* rEyeCascade;

CvMemStorage* storage;

CvCapture *capture;
IplImage *small_image;
IplImage *gray_image;

extern int getFaceBox;
extern int leftEyeX, leftEyeY, rightEyeX, rightEyeY;

int leftRedMin; int leftRedMax;
int leftGreenMin; int leftGreenMax;
int leftBlueMin; int leftBlueMax;

int rightRedMin; int rightRedMax;
int rightGreenMin; int rightGreenMax;
int rightBlueMin; int rightBlueMax;

int leftMin; int leftMax;
int rightMin; int rightMax;

int rMax;
int gMin;
int gMax;
int bMin;
int bMax;
int clicks;

// Defined events for mouse interactions
// Grayscale
void mouseCallBack(int event, int x, int y, int flags, void* param)
{
	//Click #1: Click on the left eye!
	IplImage *image = (IplImage *)(*((IplImage **)param));
	cvCvtColor (image, gray_image, CV_BGR2GRAY);
	if (event == CV_EVENT_LBUTTONUP && clicks == 0) {
		leftEyeX = x;
		leftEyeY = y;

		// Gets range of pixelvalues for the left iris
		leftMin = getPixle(gray_image, leftEyeX, leftEyeY) - THRESHOLD;
		leftMax = getPixle(gray_image, leftEyeX, leftEyeY) + THRESHOLD;

		//printf("Left:  ");
		//printf("RedMin %i ", leftRedMin);
		//printf("GreenMin %i ", leftGreenMin);
		//printf("BlueMin %i ", leftBlueMin);
		clicks++;
	}
	// Click #2: Click on the right eye! 
	else if (event == CV_EVENT_LBUTTONUP && clicks == 1){
		getFaceBox = 0;
		rightEyeX = x;
		rightEyeY = y;

		// Gets range of pixelvalues for the right iris
		rightMin = getPixle(gray_image, rightEyeX, rightEyeY) - THRESHOLD;
		rightMax = getPixle(gray_image, rightEyeX, rightEyeY) + THRESHOLD;

		//printf("\nRight:  ");
		//printf("RedMin %i ", rightRedMin);
		//printf("GreenMin %i ", rightGreenMin);
		//printf("BlueMin %i ", rightBlueMin);
	 }
}

// Color

void mouseCallBack_color(int event, int x, int y, int flags, void* param)
{
	//Click #1: Click on the left eye!
	IplImage *image = (IplImage *)(*((IplImage **)param));
	if (event == CV_EVENT_LBUTTONUP && clicks == 0) {
		leftEyeX = x;
		leftEyeY = y;

		// Gets range of pixelvalues for the left iris
		leftRedMin = getRedPixle(image, leftEyeX, leftEyeY) - THRESHOLD;
		leftRedMax = getRedPixle(image, leftEyeX, leftEyeY) + THRESHOLD;

		leftGreenMin = getGreenPixle(image, leftEyeX, leftEyeY) - THRESHOLD;
		leftGreenMax = getGreenPixle(image, leftEyeX, leftEyeY) + THRESHOLD;

		leftBlueMin = getBluePixle(image, leftEyeX, leftEyeY) - THRESHOLD;
		leftBlueMax = getBluePixle(image, leftEyeX, leftEyeY) + THRESHOLD;
		//printf("Left:  ");
		//printf("RedMin %i ", leftRedMin);
		//printf("GreenMin %i ", leftGreenMin);
		//printf("BlueMin %i ", leftBlueMin);
		clicks++;
	}
	// Click #2: Click on the right eye! 
	else if (event == CV_EVENT_LBUTTONUP && clicks == 1){
		getFaceBox = 0;
		rightEyeX = x;
		rightEyeY = y;

		// Gets range of pixelvalues for the right iris
		rightRedMin = getRedPixle(image, rightEyeX, rightEyeY) - THRESHOLD;
		rightRedMax = getRedPixle(image, rightEyeX, rightEyeY) + THRESHOLD;

		rightGreenMin = getGreenPixle(image, rightEyeX, rightEyeY) - THRESHOLD;
		rightGreenMax = getGreenPixle(image, rightEyeX, rightEyeY) + THRESHOLD;

		rightBlueMin = getBluePixle(image, rightEyeX, rightEyeY) - THRESHOLD;
		rightBlueMax = getBluePixle(image, rightEyeX, rightEyeY) + THRESHOLD;
		//printf("\nRight:  ");
		//printf("RedMin %i ", rightRedMin);
		//printf("GreenMin %i ", rightGreenMin);
		//printf("BlueMin %i ", rightBlueMin);
	 }
}

int setUpFaceFinder()
{
	clicks = 0;
	//cvNamedWindow( "win",CV_WINDOW_AUTOSIZE | CV_GUI_NORMAL); //Creates A window to draw the image to
	//cvNamedWindow( "l eye win",CV_WINDOW_AUTOSIZE | CV_GUI_NORMAL); //Creates A window to draw the eye to, for testing
	//cvNamedWindow( "r eye win",CV_WINDOW_AUTOSIZE | CV_GUI_NORMAL); //Creates A window to draw the eye to, for testing

	cvNamedWindow( "win", CV_GUI_NORMAL);
	cvSetWindowProperty("win", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);

	//small_image = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 1);
	//cvRectangle(small_image, cvPoint(0,0), cvPoint(100,100), cvScalar(255), CV_FILLED);
	//cvShowImage( "win", small_image);

	cvInitFont(&myFont,CV_FONT_HERSHEY_COMPLEX_SMALL ,1.0f, 1.0f, 0, 1, 8); // Sets up the font

	// load the cascades
	faceCascade = (CvHaarClassifierCascade*) cvLoad ("haarcascade_frontalface_alt2.xml", 0, 0, 0);
    lEyeCascade = (CvHaarClassifierCascade*) cvLoad ("haarcascade_leftEye.xml", 0, 0, 0);
	rEyeCascade = (CvHaarClassifierCascade*) cvLoad ("haarcascade_rightEye.xml", 0, 0, 0);
	
	// sotrage to be used later by opencv
	storage = cvCreateMemStorage(0);
    assert (storage);

	// capure for getting the imge from the camera.
	capture =  cvCaptureFromCAM(1);

	faceRec = (CvRect*)malloc(sizeof(CvRect));
	lEyeRec = (CvRect*)malloc(sizeof(CvRect));
	rEyeRec = (CvRect*)malloc(sizeof(CvRect));

	// did we load the cascade?!?
    if (!faceCascade || !lEyeCascade || !rEyeCascade)
        return 1;

	return 0;
}

// Grayscale Eye Position 

void getEyesPos(IplImage *image, CvPoint2D32f *leye, CvPoint2D32f *reye)
{
	float lxSum = 0.0; 
	float rxSum = 0.0;
	float lySum = 0.0;
	float rySum = 0.0;
	float lCount = 0.0;
	float rCount = 0.0;
	cvCvtColor (image, gray_image, CV_BGR2GRAY);
		
	for (int i = lEyeRec->x; i < lEyeRec->x + lEyeRec->width; i++) {
		for (int j = lEyeRec->y; j < lEyeRec->y + lEyeRec->height; j++) {
			int pix = getPixle(gray_image, i, j);

			if (pix >= leftMin && pix <= leftMax)
			{
					lxSum += i;
					lySum += j;
					lCount++;
					//setRedPixle(image, i, j, 0);
					//setGreenPixle(image, i, j, 255);
					//setBluePixle(image, i, j, 0);
			}
		}
	}
		
	for (int i = rEyeRec->x; i < rEyeRec-> x + rEyeRec->width; i++) {
		for (int j = rEyeRec->y; j < rEyeRec->y + rEyeRec->height; j++) {
			int pix = getPixle(gray_image, i, j);

			if (pix >= leftMin && pix <= leftMax)
			{
					rxSum += i;
					rySum += j;
					rCount++;
					//setRedPixle(image, i, j, 0);
					//setGreenPixle(image, i, j, 255);
					//setBluePixle(image, i, j, 0);
			}

		}
	}

	if (lCount) {
		leye->x = lxSum / lCount;
		leye->y = lySum / lCount;
	} else {
		leye->x = 0.0;
		leye->y = 0.0;
	}

	if (rCount) {
		reye->x = rxSum / rCount;
		reye->y = rySum / rCount;
	} else {
		reye->x = 0.0;
		reye->y = 0.0;
	}
}


// Color Eye Position

void getEyesPos_color(IplImage *image, CvPoint2D32f *leye, CvPoint2D32f *reye)
{
	float lxSum = 0.0; 
	float rxSum = 0.0;
	float lySum = 0.0;
	float rySum = 0.0;
	float lCount = 0.0;
	float rCount = 0.0;
		
	for (int i = lEyeRec->x; i < lEyeRec->x + lEyeRec->width; i++) {
		for (int j = lEyeRec->y; j < lEyeRec->y + lEyeRec->height; j++) {
			int red = getRedPixle(image, i, j);
			int blue = getBluePixle(image, i, j);
			int green = getGreenPixle(image, i, j);

			if (red >= leftRedMin && red <= leftRedMax &&
				blue >= leftBlueMin && blue <= leftBlueMax &&
				green >= leftGreenMin && green <= leftGreenMax) {
					lxSum += i;
					lySum += j;
					lCount++;
					setRedPixle(image, i, j, 0);
					setGreenPixle(image, i, j, 255);
					setBluePixle(image, i, j, 0);
			}
		}
	}
		
	for (int i = rEyeRec->x; i < rEyeRec-> x + rEyeRec->width; i++) {
		for (int j = rEyeRec->y; j < rEyeRec->y + rEyeRec->height; j++) {
			int red = getRedPixle(image, i, j);
			int blue = getBluePixle(image, i, j);
			int green = getGreenPixle(image, i, j);

			if (red >= rightRedMin && red <= rightRedMax &&
				blue >= rightBlueMin && blue <= rightBlueMax &&
				green >= rightGreenMin && green <= rightGreenMax) {
					rxSum += i;
					rySum += j;
					rCount++;
					setRedPixle(image, i, j, 0);
					setGreenPixle(image, i, j, 255);
					setBluePixle(image, i, j, 0);
			}

		}
	}

	if (lCount) {
		leye->x = lxSum / lCount;
		leye->y = lySum / lCount;
	} else {
		leye->x = 0.0;
		leye->y = 0.0;
	}

	if (rCount) {
		reye->x = rxSum / rCount;
		reye->y = rySum / rCount;
	} else {
		reye->x = 0.0;
		reye->y = 0.0;
	}
}

int getFaceRec(IplImage *current_frame)
{
	CvSeq* faces = cvHaarDetectObjects (current_frame, faceCascade, storage,
										1.3, 2,CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_CANNY_PRUNING,
										cvSize (30, 30));

		
	if (!faces->total) {
		cvClearMemStorage(storage);
		return 0;
	} else {
		CvRect* rec = (CvRect*) cvGetSeqElem (faces, 0);
		faceRec->x = rec->x;
		faceRec->y = rec->y;
		faceRec->width = rec->width;
		faceRec->height = rec->height;


		//cvRectangle(current_frame, cvPoint(faceRec->x, faceRec->y), cvPoint(faceRec->x + faceRec->width, faceRec->y + faceRec->height), CV_RGB(255,0,0), 1, 8, 0);
		
		// set the roi to be the face
		cvSetImageROI(current_frame, cvRect(faceRec->x, faceRec->y, faceRec->width*.5, faceRec->height*.5));
		

		CvSeq* lEyes = cvHaarDetectObjects (current_frame, lEyeCascade, storage,
											1.3, 2,CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_CANNY_PRUNING,
											cvSize (30, 30));
	
		cvResetImageROI(current_frame);
		cvSetImageROI(current_frame, cvRect(faceRec->x +  faceRec->width*.5, faceRec->y, faceRec->width*.5, faceRec->height*.5));

		CvSeq* rEyes = cvHaarDetectObjects (current_frame, rEyeCascade, storage,
											1.3, 2,CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_CANNY_PRUNING,
											cvSize (30, 30));

		if (rEyes->total) {
			rec = (CvRect*)cvGetSeqElem (rEyes, 0);
			rEyeRec->x = rec->x;
			rEyeRec->y = rec->y;
			rEyeRec->width = rec->width;
			rEyeRec->height = rec->height;
		}

		if (lEyes->total) {
			rec = (CvRect*)cvGetSeqElem (lEyes, 0);
			lEyeRec->x = rec->x;
			lEyeRec->y = rec->y;
			lEyeRec->width = rec->width;
			lEyeRec->height = rec->height;
		}
	}
	cvResetImageROI(gray_image);
	cvClearMemStorage(storage);
	return 1;
}

